home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / graphic / pcxut10.zip / PCXUTILS.C < prev    next >
C/C++ Source or Header  |  1993-08-08  |  19KB  |  500 lines

  1. /* A few simple conversions for monochrome & 16-color PCX files
  2.  
  3.    PCXUTILS is meant to deal with pcx-files produced by DrawPerfect,
  4.    WP Presentations, Harvard Graphics and GhostScript.
  5.    Output should be usable for WordPerfect and TeX.
  6.    Problems which occur with these programs:
  7.    - GhostScript doesn't always produce an even n. of bytes
  8.    - Harvard Graphics does something funny with the palette
  9.    - WordPerfect and some other programs seem to compute bytes/line from
  10.      image width instead of reading it directly from the header
  11.    - Many graphics programs can't produce monochrome bitmaps, causing
  12.      unnecessarily large filesizes
  13.  
  14.    PCXUTILS does the following:
  15.    /i:  invert
  16.    /m:  color to monochrome: every non-white color becomes black;
  17.         use this option only when the bitmap has a standard palette
  18.         apply successive /i /m /i transformations if you want
  19.         to map every non-black color to white
  20.    /r:  round image size up to even n. of bytes per line
  21.    /p+: standardize palette by interpreting existing palette; equivalent to /p
  22.    /p-: standardize palette and ignore existing palette
  23.    Only the first switch is honored.
  24.    Irrespective of options:
  25.    - round bytes/line up to even number (irrespective of image size)
  26.    - reduce bytes/line to smallest possible number
  27.  
  28.    Compiler: Turbo C++ 3.0
  29. */
  30.  
  31. /* standard header files */
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <alloc.h>
  36. #include <dos.h>
  37. #include <dir.h>
  38. #include <errno.h>
  39.  
  40. #define FALSE 0
  41. #define TRUE 1
  42. #define LOBYTE(x) (*(unsigned char *)&(x))
  43. #define HIBYTE(x) (*(((unsigned char *)&(x))+1))
  44.  
  45. void errexit0 (char *message);
  46. void errexit1 (char *message);
  47.  
  48. int prcount, swcount, parinx, swinx;
  49. void cmdline(void); /* find command-line switch and parameter */
  50.  
  51. void helpinfo(void);
  52. void make_palette(void);
  53.  
  54. /* PCX file header */
  55. typedef struct
  56. { char manufacturer;
  57.   char version;
  58.   char encoding;
  59.   char bits_per_pixel;
  60.   int  xmin,ymin;
  61.   int  xmax,ymax;
  62.   int  hres,vres;
  63.   unsigned char palette[48];
  64.   char reserved;
  65.   char color_planes;
  66.   int  bytes_per_line;
  67.   int  palette_type;
  68.   char filler[58];
  69. } PCXHEAD;
  70.  
  71. PCXHEAD header;
  72.  
  73. /* The following typedefs and data make it possible to determine
  74.    pixel values without actual unpacking */
  75. typedef union
  76. { unsigned long l;
  77.   unsigned char c[4];
  78. } MASK; /* for each colorplane one byte */
  79. typedef MASK MASKARRAY[8];
  80. MASKARRAY masks; /* masks to isolate each pixel for each bit position */
  81. MASKARRAY maskpalette[16]; /* (color code, bit position) -> MASK */
  82. MASKARRAY newpalette[16]; /* (new color code, bit position) -> MASK */
  83.  
  84. /* available processing options */
  85. enum options { opt_tomono, opt_round, opt_invert, opt_pal_ignore,
  86.   opt_pal_arrng, opt_none };
  87. int pr_opt; /* selected processing option */
  88.  
  89. FILE *in, *out;
  90.  
  91. /* properties input file: */
  92. int old_bpl; /* old value for bytes_per_line */
  93. int bpl_tot; /* bytes per line times color planes */
  94. int old_width; /* old picture width */
  95. int monoin; /* input file is mono */
  96. int chg_bpl; /* bytes per line requires changing */
  97. int palet_funny; /* palette anomalies; implies !mono && header.version!=3 */
  98. char pcxpath[MAXPATH], oldpath[MAXPATH]; /* full filenames */
  99. char old_pal[48]; /* old palette */
  100. unsigned char *const hpal = (unsigned char *)&header.palette;
  101.   /* for easy reference to header palette */
  102. char const std_pal[48] = /* a more or less standard EGA palette */
  103. { 0x0,0x0,0x0,    0x0,0x0,0x80,  0x0,0x80,0x0,  0x0,0x80,0x80,
  104.   0x80,0x0,0x0,   0x80,0x0,0x80, 0x80,0x80,0x0, 0x80,0x80,0x80,
  105.   0x40,0x40,0x40, 0x0,0x0,0xff,  0x0,0xff,0x0,  0x0,0xff,0xff,
  106.   0xff,0x0,0x0,   0xff,0x0,0xff, 0xff,0xff,0x0, 0xff,0xff,0xff };
  107.  
  108. typedef unsigned char *LINE;
  109. LINE plane[4]; /* up to 4 bitplanes, yet to be allocated */
  110. unsigned char *pl; /* pointer into plane */
  111.  
  112. void main (int argc, char *argv[])
  113.  
  114. { int c,i,j,k,l;
  115.   union { unsigned char ch[2]; unsigned int intg; } endmask;
  116.   MASK eachplane; /* one byte from each plane */
  117.   MASK thispixel;
  118.   cmdline();
  119.   if (prcount>1) puts ("Excess command-line parameters ignored");
  120.   if (swcount>1) puts ("Excess command-line switches ignored");
  121.  
  122.   /* header input file */
  123.   if (prcount<1) helpinfo();
  124.   { char fndrive[MAXDRIVE];
  125.     char fndir[MAXDIR];
  126.     char fnfile[MAXFILE];
  127.     fnsplit
  128.       (argv[parinx],(char *)fndrive,(char *)fndir,(char *)fnfile,NULL);
  129.     fnmerge (pcxpath,(char *)fndrive,(char *)fndir,(char *)fnfile,".PCX");
  130.     fnmerge (oldpath,(char *)fndrive,(char *)fndir,(char *)fnfile,".OLD");
  131.   }
  132.   in = fopen (pcxpath,"rb");
  133.   if (!in) errexit0("Access failure input file");
  134.   if (fread((char *)&header,1,sizeof(PCXHEAD),in)!=sizeof(PCXHEAD))
  135.     errexit0("Failure to read PCX file");
  136.   fclose(in); /* later, we reopen the file as *.old */
  137.   if (header.manufacturer!=0x0a) errexit0("Not a PCX file");
  138.   if (header.bits_per_pixel!=1) errexit0("Format not supported");
  139.     /* this might be changed later on */
  140.   if (header.color_planes==1) monoin = TRUE;
  141.   else if (header.color_planes==4) monoin = FALSE;
  142.   else errexit0("Format not supported");
  143.  
  144.   /* standard palette: 1rst color 0,0,0 last ff,ff,ff; all colors different */
  145.   palet_funny=FALSE;
  146.   memmove(old_pal,header.palette,48);
  147.   if (header.version!=3 && !monoin)
  148.   { for (i=0;i<3;i++) if (header.palette[i]!=0)
  149.       { palet_funny=TRUE; break; }
  150.     if (!palet_funny) for (i=45;i<48;i++) if (header.palette[i]!=255)
  151.       { palet_funny=TRUE; break; }
  152.     if (!palet_funny) for (i=0;i<48;i+=3) /* entries all different? */
  153.       { for (j=0;j<i;j+=3)
  154.           if (old_pal[i]==old_pal[j]
  155.            && old_pal[i+1]==old_pal[j+1]
  156.            && old_pal[i+2]==old_pal[j+2]) { palet_funny=TRUE; break; }
  157.         if (palet_funny) break;
  158.       }
  159.   }
  160.  
  161.   /* image width and bytes_per_line */
  162.   old_width=header.xmax-header.xmin+1;
  163.   if (old_width<=0 || header.ymax<header.ymin)
  164.     errexit0("Error: Picture has zero height or width");
  165.   old_bpl = header.bytes_per_line;
  166.   chg_bpl = (old_bpl%2) || (old_bpl*8-old_width*header.bits_per_pixel>15);
  167.  
  168.   in = NULL; out = NULL;
  169.  
  170.   /* decode switch; start comparing after first character ('/' or '-') */
  171.   pr_opt = opt_none;
  172.   if (swcount>0)
  173.   { if (!stricmp(argv[swinx]+1,"r")) pr_opt = opt_round;
  174.     else if (!stricmp(argv[swinx]+1,"i")) pr_opt = opt_invert;
  175.     else if (!stricmp(argv[swinx]+1,"m")) pr_opt = opt_tomono;
  176.     else if (!stricmp(argv[swinx]+1,"p+")||
  177.              !stricmp(argv[swinx]+1,"p")) pr_opt = opt_pal_arrng;
  178.     else if (!stricmp(argv[swinx]+1,"p-")) pr_opt = opt_pal_ignore;
  179.     else helpinfo();
  180.   }
  181.  
  182.   /* sort out actions; report to user */
  183.  
  184.     /* comments on header */
  185.  
  186.   if (palet_funny && pr_opt!=opt_pal_ignore && pr_opt!=opt_pal_arrng)
  187.     puts("Non-standard palette;\n"
  188.       "if results unsatisfactory try a preliminary PCXUTILS /p run");
  189.   if (chg_bpl) puts ("Correcting bytes/line");
  190.  
  191.     /* options */
  192.  
  193.   if (pr_opt==opt_tomono)
  194.   { if (monoin) { puts("Bitmap already mono"); pr_opt = opt_none; }
  195.     else puts("Converting to monochrome");
  196.   }
  197.   else if (pr_opt==opt_round)
  198.   { if (old_width*header.bits_per_pixel==8*old_bpl && !chg_bpl)
  199.     { puts("Image width is already rounded to match bytes/line");
  200.       pr_opt = opt_none; }
  201.     else puts("Rounding image width");
  202.   }
  203.   else if (pr_opt==opt_invert) puts("Inverting colors");
  204.  
  205.   else if (pr_opt==opt_pal_ignore)
  206.   { if (monoin) { puts("Monochrome bitmap"); pr_opt = opt_none; }
  207.     else if (header.version==3)
  208.       puts("No palette; bitmap gets standard palette");
  209.     else if (!palet_funny) { puts("Palette ok"); pr_opt = opt_none; }
  210.     else puts("Bitmap gets standard palette; original palette ignored");
  211.   }
  212.  
  213.   else if (pr_opt==opt_pal_arrng)
  214.   { if (monoin) { puts("Monochrome bitmap"); pr_opt = opt_none; }
  215.     else if (header.version==3)
  216.     { pr_opt = opt_pal_ignore;
  217.       puts("No palette; bitmap gets standard palette");
  218.     }
  219.     else if (!palet_funny) { puts("Palette ok"); pr_opt = opt_none; }
  220.     else puts("Palette will be standardized by rearranging original pal